package com.zbl.zblproject.pay.service.impl;

import com.alipay.demo.trade.model.GoodsDetail;
import com.alipay.demo.trade.model.builder.AlipayTradePayRequestBuilder;
import com.alipay.demo.trade.model.result.AlipayF2FPayResult;

import com.alipay.demo.trade.service.AlipayTradeService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;

import com.github.wxpay.sdk.WXPayConstants;

import com.google.common.base.Preconditions;
import com.google.common.base.Strings;

import com.zbl.zblproject.core.entity.AdminUser;
import com.zbl.zblproject.core.entity.SnowFlake;
import com.zbl.zblproject.erp.entity.ErpGoods;
import com.zbl.zblproject.erp.mapper.ErpGoodMapper;
import com.zbl.zblproject.pay.entity.PayOrder;
import com.zbl.zblproject.pay.entity.PayOrderItem;
import com.zbl.zblproject.pay.entity.WXPayClient;
import com.zbl.zblproject.pay.mapper.PayOrderItemMapper;
import com.zbl.zblproject.pay.mapper.PayOrderMapper;
import com.zbl.zblproject.pay.service.PayService;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;

/**
 * @author youlanqiang
 * @version 1.0
 * @date 2018/11/5
 * 支付
 */
@Service
@Transactional
public class PayServiceImpl implements PayService {


    private static final Logger logger = LoggerFactory.getLogger(PayService.class);

    @Autowired
    private PayOrderMapper payOrderMapper;

    @Autowired
    private PayOrderItemMapper payOrderItemMapper;

    @Autowired
    private ErpGoodMapper erpGoodMapper;


    @Autowired
    private SnowFlake snowFlake;

    @Autowired
    private AlipayTradeService alipayTradeService;

    @Autowired
    private WXPayClient wxPayClient;

    @Override
    public boolean changeOrderToRefund(PayOrder order) {
        if(order.getStatus() == 0){
            return false;
        }
        order.setStatus(2);
        return payOrderMapper.updateById(order) == 1;
    }

    @Override
    public PayOrder getOrderByOnlineSn(String orderSn) {
        QueryWrapper<PayOrder> wrapper = new QueryWrapper<>();
        wrapper.eq("online_order_sn", orderSn);
        return payOrderMapper.selectOne(wrapper);
    }

    @Override
    public void createBaseOrder(final AdminUser user, final PayOrder order) {
        if (order.getCreateTime() == null) {
            order.setCreateTime(LocalDateTime.now());
        }
        order.setUserId(user.getUserId());
        boolean result = payOrderMapper.insert(order) == 1;
        if (!result) {
            throw new RuntimeException("订单添加失败!");
        }
        for (PayOrderItem item : order.getItems()) {
            item.setId(snowFlake.nextId());
            item.setGoodsName(erpGoodMapper.getGoodsNameByGoodsId(item.getGoodsId()));
            item.setOrderId(order.getId());
            result = payOrderItemMapper.insert(item) == 1;
            Preconditions.checkArgument(result, "订单项添加失败!");
        }
    }

    @Override
    public void createBaseOrders(final AdminUser user, final List<PayOrder> orders) {
        if (orders.isEmpty()) {
            throw new RuntimeException("没有需要更新的订单项");
        }
        //0: 现金 1:支付宝 2:微信 3:银联
        for (PayOrder order : orders) {
            order.setId(snowFlake.nextId());
            switch (order.getMode()) {
                case 1: //支付宝
                    alipay(user, order);
                    break;
                case 2: //微信
                    weixin(user, order);
                    break;
                case 3: //银联
                    union(user, order);
                    break;
                default: //基础订单
                    order.setStatus(1);
                    createBaseOrder(user, order);
                    break;
            }
        }
    }


    @Override
    public String alipay(final AdminUser user, final PayOrder order) {
        if (Strings.isNullOrEmpty(order.getPayCode())) {
            throw new RuntimeException("支付宝用户付款码不存在!");
        }
        if(order.getStatus() == 1){
            throw new RuntimeException("订单支付方式异常!");
        }
        if(barCodePay(user, order)){
            order.setStatus(1);
            createBaseOrder(user, order);
            //返回订单的交易号.
            return order.getOnlineOrderSn();
        }
        throw new RuntimeException("支付宝,支付失败!");
    }

    /**
     * 支付宝支付
     * @param order

     * @return
     */
    private boolean barCodePay(final AdminUser adminUser, final PayOrder order) {

        // (必填) 商户网站订单系统中唯一订单号，64个字符以内，只能包含字母、数字、下划线，
        String outTradeNo = UUID.randomUUID().toString();

        //设置订单号
        order.setOnlineOrderSn(outTradeNo);

        // (必填) 订单标题，粗略描述用户的支付目的。如“喜士多（浦东店）消费”
        String subject = adminUser.getStoreName() + "门店消费";


        // (必填) 订单总金额，单位为元，不能超过1亿元 实际收
        String totalAmount = String.valueOf(order.getOfficialReceipts().doubleValue());

        // 订单描述，
        String body = "购买了" + order.getItems().size() + "件商品,消费" + totalAmount + "元.";


        // (必填) 商户门店编号，通过门店号和商家后台可以配置精准到门店的折扣信息，详询支付宝技术支持
        String storeId = String.valueOf(adminUser.getUserId());

        // 商品明细列表，需填写购买商品详细信息，
        List<GoodsDetail> goodsDetailList = new ArrayList<>();

        ErpGoods goods;
        for(PayOrderItem item : order.getItems()){
            goods = erpGoodMapper.selectById(item.getGoodsId());
            GoodsDetail goods1 = GoodsDetail.newInstance("商品ID:"+goods.getGoodsId(), goods.getGoodsName(), item.getSinglePrice().multiply(new BigDecimal(100)).longValue(), item.getGoodsNum());
            goodsDetailList.add(goods1);
        }

        // 支付超时，线下扫码交易定义为5分钟
        String timeoutExpress = "5m";


        AlipayTradePayRequestBuilder builder = new AlipayTradePayRequestBuilder()
                .setOutTradeNo(outTradeNo)
                .setSubject(subject)
                .setBody(body)
                .setTotalAmount(totalAmount)
                .setAuthCode(order.getPayCode())
                .setTotalAmount(totalAmount)
                .setStoreId(storeId)
                .setGoodsDetailList(goodsDetailList)
                .setTimeoutExpress(timeoutExpress);

        // 当面付，面对面付，face to face pay -> face 2 face pay -> f2f pay
        // 同步返回支付结果

        AlipayF2FPayResult f2FPayResult = alipayTradeService.tradePay(builder);
        // 注意：一定要处理支付的结果，因为不是每次支付都一定会成功，可能会失败
        switch (f2FPayResult.getTradeStatus()) {
            case SUCCESS:
                logger.info("支付宝支付成功!");
                return true;

            case FAILED:
                logger.error("支付宝支付失败!!!");
                return false;

            case UNKNOWN:
                logger.error("系统异常，订单状态未知!!!");
                return false;

            default:
                logger.error("不支持的交易状态，交易返回异常!!!");
                return false;
        }
    }


    @Override
    public void weixin(final AdminUser user, final PayOrder order) {
        if(order.getStatus() != 2){
            throw new RuntimeException("订单支付状态异常!");
        }
        Map<String, String> reqData = new HashMap<>();
        // 商户订单号
        String outTradeNo = UUID.randomUUID().toString();
        order.setOnlineOrderSn(outTradeNo);
        reqData.put("out_trade_no", outTradeNo);
        // 订单总金额，单位为分，只能为整数
        reqData.put("total_fee", String.valueOf(order.getOfficialReceipts().multiply(new BigDecimal(100)).longValue()));
        // 授权码
        reqData.put("auth_code", order.getPayCode());
        // 商品描述
        reqData.put("body", "购买了" + order.getItems().size() + "件商品,消费" + order.getOfficialReceipts() + "元.");
        try {
            Map<String, String> resultMap = wxPayClient.microPayWithPOS(reqData);
            logger.info(resultMap.toString());
            if(WXPayConstants.SUCCESS.equals(resultMap.get("return_code"))){
                createBaseOrder(user, order);
            }else{
                throw new RuntimeException("微信订单支付失败!");
            }
        }catch(Exception e){
            throw new RuntimeException(e.getMessage());
        }
    }

    @Override
    public void union(final AdminUser user, final PayOrder order) {
        //TODO 银联接口未完成
        throw new RuntimeException("银联接口未完成!");
    }


    @Override
    public BigDecimal returnAlipayItems(List<PayOrderItem> list) {
        //TODO 创建一个退款记录

        return BigDecimal.ZERO;
    }

    @Override
    public String getPayOrderOnlineOrder(String orderSn) {
        return payOrderMapper.selectOnlineOrderOfPayOrder(orderSn);
    }
}
